home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / aipath.c < prev    next >
C/C++ Source or Header  |  1998-03-03  |  56KB  |  1,605 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/aipath.c,v $
  15.  * $Revision: 1.1.1.1 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/03/03 15:12:11 $
  18.  * 
  19.  * AI path forming stuff.
  20.  * 
  21.  * $Log: aipath.c,v $
  22.  * Revision 1.1.1.1  1998/03/03 15:12:11  nobody
  23.  * reimport after crash from backup
  24.  *
  25.  * Revision 1.1.1.1  1998/02/13  20:20:38  hfrieden
  26.  * Initial Import
  27.  *
  28.  * Revision 2.0  1995/02/27  11:30:48  john
  29.  * New version 2.0, which has no anonymous unions, builds with
  30.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  31.  * 
  32.  * Revision 1.101  1995/02/22  13:42:44  allender
  33.  * remove anonymous unions for object structure
  34.  * 
  35.  * Revision 1.100  1995/02/10  16:20:04  mike
  36.  * fix bogosity in create_path_points, assumed all objects were robots.
  37.  * 
  38.  * Revision 1.99  1995/02/07  21:09:30  mike
  39.  * make run_from guys have diff level based speed.
  40.  * 
  41.  * Revision 1.98  1995/02/04  17:28:29  mike
  42.  * make station guys return better.
  43.  * 
  44.  * Revision 1.97  1995/02/04  10:28:39  mike
  45.  * fix compile error!
  46.  * 
  47.  * Revision 1.96  1995/02/04  10:03:37  mike
  48.  * Fly to exit cheat.
  49.  * 
  50.  * Revision 1.95  1995/02/01  21:10:36  mike
  51.  * Array name was dereferenced.  Not a bug, but unclean.
  52.  * 
  53.  * Revision 1.94  1995/02/01  17:14:12  mike
  54.  * comment out some common mprintfs which didn't matter.
  55.  * 
  56.  * Revision 1.93  1995/01/30  13:01:23  mike
  57.  * Make robots fire at player other than one they are controlled by sometimes.
  58.  * 
  59.  * Revision 1.92  1995/01/29  22:29:32  mike
  60.  * add more debug info for guys that get lost.
  61.  * 
  62.  * Revision 1.91  1995/01/20  16:56:05  mike
  63.  * station stuff.
  64.  * 
  65.  * Revision 1.90  1995/01/18  10:59:45  mike
  66.  * comment out some mprintfs.
  67.  * 
  68.  * Revision 1.89  1995/01/17  16:58:34  mike
  69.  * make path following work for multiplayer.
  70.  * 
  71.  * Revision 1.88  1995/01/17  14:21:44  mike
  72.  * make run_from guys run better.
  73.  * 
  74.  * Revision 1.87  1995/01/14  17:09:04  mike
  75.  * playing with crazy josh, he's kinda slow and dumb now.
  76.  * 
  77.  * Revision 1.86  1995/01/13  18:52:28  mike
  78.  * comment out int3.
  79.  * 
  80.  * Revision 1.85  1995/01/05  09:42:11  mike
  81.  * compile out code based on SHAREWARE.
  82.  * 
  83.  * Revision 1.84  1995/01/02  12:38:32  mike
  84.  * make crazy josh turn faster, therefore evade player better.
  85.  * 
  86.  * Revision 1.83  1994/12/27  15:59:40  mike
  87.  * tweak ai_multiplayer_awareness constants.
  88.  * 
  89.  * Revision 1.82  1994/12/19  17:07:10  mike
  90.  * deal with new ai_multiplayer_awareness which returns a value saying whether this object can be moved by this player.
  91.  * 
  92.  * Revision 1.81  1994/12/15  13:04:30  mike
  93.  * Replace Players[Player_num].time_total references with GameTime.
  94.  * 
  95.  * Revision 1.80  1994/12/09  16:13:23  mike
  96.  * remove debug code.
  97.  * 
  98.  * Revision 1.79  1994/12/07  00:36:54  mike
  99.  * make robots get out of matcens better and be aware of player.
  100.  * 
  101.  * Revision 1.78  1994/11/30  00:59:05  mike
  102.  * optimizations.
  103.  * 
  104.  * Revision 1.77  1994/11/27  23:13:39  matt
  105.  * Made changes for new mprintf calling convention
  106.  * 
  107.  * Revision 1.76  1994/11/23  21:59:34  mike
  108.  * comment out some mprintfs.
  109.  * 
  110.  * Revision 1.75  1994/11/21  16:07:14  mike
  111.  * flip PARALLAX flag, prevent annoying debug information.
  112.  * 
  113.  * Revision 1.74  1994/11/19  15:13:28  mike
  114.  * remove unused code and data.
  115.  * 
  116.  * Revision 1.73  1994/11/17  14:53:15  mike
  117.  * segment validation functions moved from editor to main.
  118.  * 
  119.  * Revision 1.72  1994/11/16  23:38:42  mike
  120.  * new improved boss teleportation behavior.
  121.  * 
  122.  * Revision 1.71  1994/11/13  17:18:30  mike
  123.  * debug code, then comment it out.
  124.  * 
  125.  * Revision 1.70  1994/11/11  16:41:43  mike
  126.  * flip the PARALLAX flag.
  127.  * 
  128.  * Revision 1.69  1994/11/11  16:33:45  mike
  129.  * twiddle the PARALLAX flag.
  130.  * 
  131.  * 
  132.  * Revision 1.68  1994/11/10  21:32:29  mike
  133.  * debug code.
  134.  * 
  135.  * Revision 1.67  1994/11/10  20:15:07  mike
  136.  * fix stupid bug: uninitialized pointer.
  137.  * 
  138.  * Revision 1.66  1994/11/10  17:45:15  mike
  139.  * debugging.
  140.  * 
  141.  * Revision 1.65  1994/11/10  17:28:10  mike
  142.  * debugging.
  143.  * 
  144.  */
  145.  
  146. #pragma off (unreferenced)
  147. static char rcsid[] = "$Id: aipath.c,v 1.1.1.1 1998/03/03 15:12:11 nobody Exp $";
  148. #pragma on (unreferenced)
  149.  
  150. #include <stdio.h>      //  for printf()
  151. #include <stdlib.h>     // for rand() and qsort()
  152. #include <string.h>     // for memset()
  153.  
  154. #include "inferno.h"
  155. #include "mono.h"
  156. #include "3d.h"
  157.  
  158. #include "object.h"
  159. #include "error.h"
  160. #include "ai.h"
  161. #include "robot.h"
  162. #include "fvi.h"
  163. #include "physics.h"
  164. #include "wall.h"
  165. #include "editor/editor.h"
  166. #include "player.h"
  167. #include "fireball.h"
  168. #include "game.h"
  169.  
  170. #define PARALLAX    0       //  If !0, then special debugging for Parallax eyes enabled.
  171.  
  172. void maybe_ai_path_garbage_collect(void);
  173.  
  174. //  Length in segments of avoidance path
  175. #define AVOID_SEG_LENGTH    7
  176.  
  177. create_random_xlate(byte *xt)
  178. {
  179.     int i;
  180.  
  181.     for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
  182.         xt[i] = i;
  183.  
  184.     for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
  185.         int j = (rand()*MAX_SIDES_PER_SEGMENT)/(RAND_MAX+1);
  186.         byte    temp_byte;
  187.         Assert((j >= 0) && (j < MAX_SIDES_PER_SEGMENT));
  188.  
  189.         temp_byte = xt[j];
  190.         xt[j] = xt[i];
  191.         xt[i] = temp_byte;
  192.     }
  193.  
  194. }
  195.  
  196. //  -----------------------------------------------------------------------------------------------------------
  197. //  Insert the point at the center of the side connecting two segments between the two points.
  198. // This is messy because we must insert into the list.  The simplest (and not too slow) way to do this is to start
  199. // at the end of the list and go backwards.
  200. void insert_center_points(point_seg *psegs, short *num_points)
  201. {
  202.     int i, last_point;
  203.  
  204.     last_point = *num_points-1;
  205.  
  206. //  printf("---------- Original points ----------\n");
  207. //  for (i=0; i<*num_points; i++)
  208. //      printf("%2i: %3i [%7.3f %7.3f %7.3f]\n", i, psegs[i].segnum, f2fl(psegs[i].point.x), f2fl(psegs[i].point.y), f2fl(psegs[i].point.z));
  209. //  printf("\n");
  210.  
  211.     for (i=last_point; i>0; i--) {
  212.         int         connect_side;
  213.         vms_vector  center_point, new_point;
  214.  
  215.         psegs[2*i] = psegs[i];
  216.         connect_side = find_connect_side(&Segments[psegs[i].segnum], &Segments[psegs[i-1].segnum]);
  217.         Assert(connect_side != -1); //  Impossible!  These two segments must be connected, they were created by create_path_points (which was created by mk!)
  218.         if (connect_side == -1)         //  Try to blow past the assert, this should at least prevent a hang.
  219.             connect_side = 0;
  220.         compute_center_point_on_side(¢er_point, &Segments[psegs[i-1].segnum], connect_side);
  221.         vm_vec_sub(&new_point, &psegs[i-1].point, ¢er_point);
  222.         new_point.x /= 16;
  223.         new_point.y /= 16;
  224.         new_point.z /= 16;
  225.         vm_vec_sub(&psegs[2*i-1].point, ¢er_point, &new_point);
  226.         psegs[2*i-1].segnum = psegs[2*i].segnum;
  227.         (*num_points)++;
  228.     }
  229.  
  230. //  printf("---------- With inserted points ----------\n");
  231. //  for (i=0; i<*num_points; i++)
  232. //      printf("%2i: %3i [%7.3f %7.3f %7.3f]\n", i, psegs[i].segnum, f2fl(psegs[i].point.x), f2fl(psegs[i].point.y), f2fl(psegs[i].point.z));
  233. //  printf("\n\n");
  234.  
  235. }
  236.  
  237. #ifdef EDITOR
  238. int Safety_flag_override = 0;
  239. int Random_flag_override = 0;
  240. int Ai_path_debug=0;
  241. #endif
  242.  
  243. //  -----------------------------------------------------------------------------------------------------------
  244. //  Create a path from objp->pos to the center of end_seg.
  245. //  Return a list of (segment_num, point_locations) at psegs
  246. //  Return number of points in *num_points.
  247. //  if max_depth == -1, then there is no maximum depth.
  248. //  If unable to create path, return -1, else return 0.
  249. //  If random_flag !0, then introduce randomness into path by looking at sides in random order.  This means
  250. //  that a path between two segments won't always be the same, unless it is unique.
  251. //  If safety_flag is set, then additional points are added to "make sure" that points are reachable.  I would
  252. //  like to say that it ensures that the object can move between the points, but that would require knowing what
  253. //  the object is (which isn't passed, right?) and making fvi calls (slow, right?).  So, consider it the more_or_less_safe_flag.
  254. //  If end_seg == -2, then end seg will never be found and this routine will drop out due to depth (probably called by create_n_segment_path).
  255. int create_path_points(object *objp, int start_seg, int end_seg, point_seg *psegs, short *num_points, int max_depth, int random_flag, int safety_flag, int avoid_seg)
  256. {
  257.     int     cur_seg;
  258.     int     sidenum;
  259.     int     qtail = 0, qhead = 0;
  260.     int     i;
  261.     byte        visited[MAX_SEGMENTS];
  262.     seg_seg seg_queue[MAX_SEGMENTS];
  263.     short       depth[MAX_SEGMENTS];
  264.     int     cur_depth;
  265.     byte        random_xlate[MAX_SIDES_PER_SEGMENT];
  266.     point_seg   *original_psegs = psegs;
  267. #ifndef NDEBUG
  268.     point_seg   *other_original_psegs = psegs;
  269. #endif
  270.  
  271. #ifndef NDEBUG
  272.     validate_all_paths();
  273. #endif
  274.  
  275. if ((objp->type == OBJ_ROBOT) && (objp->ctype.ai_info.behavior == AIB_RUN_FROM)) {
  276.     random_flag = 1;
  277.     avoid_seg = ConsoleObject->segnum;
  278.     // Int3();
  279. }
  280.  
  281.     if (max_depth == -1)
  282.         max_depth = MAX_PATH_LENGTH;
  283.  
  284.     *num_points = 0;
  285. //random_flag = Random_flag_override; //!! debug!!
  286. //safety_flag = Safety_flag_override; //!! debug!!
  287.  
  288. //  for (i=0; i<=Highest_segment_index; i++) {
  289. //      visited[i] = 0;
  290. //      depth[i] = 0;
  291. //  }
  292.     memset(visited, 0, sizeof(visited[0])*(Highest_segment_index+1));
  293.     memset(depth, 0, sizeof(depth[0])*(Highest_segment_index+1));
  294.  
  295.     //  If there is a segment we're not allowed to visit, mark it.
  296.     if (avoid_seg != -1) {
  297.         Assert(avoid_seg <= Highest_segment_index);
  298.         if ((start_seg != avoid_seg) && (end_seg != avoid_seg)) {
  299.             visited[avoid_seg] = 1;
  300.             depth[avoid_seg] = 0;
  301.         }
  302.     }
  303.  
  304.     if (random_flag)
  305.         create_random_xlate(random_xlate);
  306.  
  307.     cur_seg = start_seg;
  308.     visited[cur_seg] = 1;
  309.     cur_depth = 0;
  310.  
  311.     while (cur_seg != end_seg) {
  312.         segment *segp = &Segments[cur_seg];
  313.  
  314.         // mprintf((0, "\n"));
  315.         for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
  316.  
  317.             int snum = sidenum;
  318.  
  319.             if (random_flag)
  320.                 snum = random_xlate[sidenum];
  321.  
  322.             if ((WALL_IS_DOORWAY(segp, snum) & WID_FLY_FLAG) || (ai_door_is_openable(objp, segp, snum))) {
  323.                 int this_seg = segp->children[snum];
  324.  
  325.                 if (!visited[this_seg]) {
  326.                     seg_queue[qtail].start = cur_seg;
  327.                     seg_queue[qtail].end = this_seg;
  328.                     visited[this_seg] = 1;
  329.                     depth[qtail++] = cur_depth+1;
  330.                     if (depth[qtail-1] == max_depth) {
  331.                         // mprintf((0, "\ndepth == max_depth == %i\n", max_depth));
  332.                         end_seg = seg_queue[qtail-1].end;
  333.                         goto cpp_done1;
  334.                     }
  335.                 }
  336.  
  337.             }
  338.         }   //  for (sidenum...
  339.  
  340.         if (qhead >= qtail) {
  341.             //  Couldn't get to goal, return a path as far as we got, which probably acceptable to the unparticular caller.
  342.             end_seg = seg_queue[qtail-1].end;
  343.             break;
  344.         }
  345.  
  346.         cur_seg = seg_queue[qhead].end;
  347.         cur_depth = depth[qhead];
  348.         qhead++;
  349.  
  350. cpp_done1: ;
  351.     }   //  while (cur_seg ...
  352.  
  353.     //  Set qtail to the segment which ends at the goal.
  354.     while (seg_queue[--qtail].end != end_seg)
  355.         if (qtail < 0) {
  356.             // mprintf((0, "\nNo path!\n"));
  357.             // printf("UNABLE TO FORM PATH");
  358.             // Int3();
  359.             return -1;
  360.         }
  361.  
  362.     #ifdef EDITOR
  363.     N_selected_segs = 0;
  364.     #endif
  365. //printf("Object #%3i, start: %3i ", objp-Objects, psegs-Point_segs);
  366.     while (qtail >= 0) {
  367.         int parent_seg, this_seg;
  368.  
  369.         this_seg = seg_queue[qtail].end;
  370.         parent_seg = seg_queue[qtail].start;
  371.         psegs->segnum = this_seg;
  372. //printf("%3i ", this_seg);
  373.         compute_segment_center(&psegs->point,&Segments[this_seg]);
  374.         psegs++;
  375.         (*num_points)++;
  376.         #ifdef EDITOR
  377.         Selected_segs[N_selected_segs++] = this_seg;
  378.         #endif
  379.  
  380.         if (parent_seg == start_seg)
  381.             break;
  382.  
  383.         while (seg_queue[--qtail].end != parent_seg)
  384.             Assert(qtail >= 0);
  385.     }
  386.  
  387.     psegs->segnum = start_seg;
  388. //printf("%3i\n", start_seg);
  389.     compute_segment_center(&psegs->point,&Segments[start_seg]);
  390.     psegs++;
  391.     (*num_points)++;
  392.  
  393. #ifndef NDEBUG
  394.     validate_path(1, original_psegs, *num_points);
  395. #endif
  396.  
  397.     //  Now, reverse point_segs in place.
  398.     for (i=0; i< (*num_points)/2; i++) {
  399.         point_seg       temp_point_seg = *(original_psegs + i);
  400.         *(original_psegs + i) = *(original_psegs + *num_points - i - 1);
  401.         *(original_psegs + *num_points - i - 1) = temp_point_seg;
  402.     }
  403. #ifndef NDEBUG
  404.     validate_path(2, original_psegs, *num_points);
  405. #endif
  406.  
  407.     //  Now, if safety_flag set, then insert the point at the center of the side connecting two segments
  408.     //  between the two points.  This is messy because we must insert into the list.  The simplest (and not too slow)
  409.     //  way to do this is to start at the end of the list and go backwards.
  410.     if (safety_flag) {
  411.         if (psegs - Point_segs + *num_points + 2 > MAX_POINT_SEGS) {
  412.             //  Ouch!  Cannot insert center points in path.  So return unsafe path.
  413. //          Int3(); // Contact Mike:  This is impossible.
  414. //          force_dump_ai_objects_all("Error in create_path_points");
  415.             ai_reset_all_paths();
  416.             return -1;
  417.         } else {
  418.             //mprintf((0, "Old num_points = %i, new one should be %i. ", *num_points, 2 * (*num_points) - 1));
  419.             insert_center_points(original_psegs, num_points);
  420.             //mprintf((0, "New num_points = %i\n", *num_points));
  421.         }
  422.     }
  423. #ifndef NDEBUG
  424.     validate_path(3, original_psegs, *num_points);
  425. #endif
  426.  
  427. #ifndef NDEBUG
  428. //--debug   if (objp == ConsoleObject) {
  429. //--debug       int i;
  430. //--debug
  431. //--debug       for (i=0; i<*num_points; i++) {
  432. //--debug           mprintf((0, "%3i ", original_psegs[i].segnum));
  433. //--debug       }
  434. //--debug       mprintf((0, "\n"));
  435. //--debug   }
  436.  
  437.     validate_path(0, original_psegs, *num_points);
  438.  
  439. // mprintf((0, "Created path for object %3i at index %4i, length = %2i\n", objp-Objects, psegs-Point_segs, *num_points));
  440.     Assert(other_original_psegs == original_psegs);
  441.  
  442. //--debug 01/18/95--    if (objp->ctype.ai_info.behavior == AIB_RUN_FROM) {
  443. //--debug 01/18/95--        int i;
  444. //--debug 01/18/95--
  445. //--debug 01/18/95--        mprintf((0, "%3i: ", objp-Objects));
  446. //--debug 01/18/95--        for (i=0; i<*num_points; i++)
  447. //--debug 01/18/95--            mprintf((0, "%3i ", original_psegs[i].segnum));
  448. //--debug 01/18/95--        mprintf((0, "\n"));
  449. //--debug 01/18/95--    }
  450. #endif
  451.  
  452.  
  453.     return 0;
  454. }
  455.  
  456. #ifndef NDEBUG
  457. #pragma off (unreferenced)
  458. //  -------------------------------------------------------------------------------------------------------
  459. //  Make sure that there are connections between all segments on path.
  460. //  Note that if path has been optimized, connections may not be direct, so this function is useless, or worse.
  461. //  Return true if valid, else return false.
  462. int validate_path(int debug_flag, point_seg *psegs, int num_points)
  463. {
  464. #if PARALLAX
  465.     int     i, curseg;
  466.  
  467.     //  Trap a common bug elsewhere in aipath.
  468.     if (psegs > Point_segs_free_ptr) {
  469.         //Int3();       //  Contact Mike: Debug trap for elusive, nasty bug.
  470.         return 0;
  471.     }
  472.  
  473.     curseg = psegs->segnum;
  474.     if ((curseg < 0) || (curseg > Highest_segment_index)) {
  475.         mprintf((0, "Path beginning at index %i, length=%i is bogus!\n", psegs-Point_segs, num_points));
  476.         return 0;
  477.     }
  478.  
  479. if (debug_flag == 999)
  480.     mprintf((0, "That's curious...\n"));
  481.  
  482. if (num_points == 0)
  483.     return 1;
  484.  
  485. // printf("(%i) Validating path at psegs=%i, num_points=%i, segments = %3i ", debug_flag, psegs-Point_segs, num_points, psegs[0].segnum);
  486.     for (i=1; i<num_points; i++) {
  487.         int sidenum;
  488.         int nextseg = psegs[i].segnum;
  489.  
  490.         if ((nextseg < 0) || (nextseg > Highest_segment_index)) {
  491.             mprintf((0, "Path beginning at index %i, length=%i is bogus!\n", psegs-Point_segs, num_points));
  492.             return 0;
  493.         }
  494.  
  495. // printf("%3i ", nextseg);
  496.         if (curseg != nextseg) {
  497.             for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
  498.                 if (Segments[curseg].children[sidenum] == nextseg)
  499.                     break;
  500.  
  501.             // Assert(sidenum != MAX_SIDES_PER_SEGMENT);    //  Hey, created path is not contiguous, why!?
  502.             if (sidenum == MAX_SIDES_PER_SEGMENT) {
  503.                 mprintf((0, "Path beginning at index %i, length=%i is bogus!\n", psegs-Point_segs, num_points));
  504.                 // printf("BOGUS");
  505.                 // Int3();
  506.                 return 0;
  507.             }
  508.             curseg = nextseg;
  509.         }
  510.     }
  511. //printf("\n");
  512. #endif
  513.     return 1;
  514.  
  515. }
  516. #pragma on (unreferenced)
  517. #endif
  518.  
  519. #ifndef NDEBUG
  520. //  -----------------------------------------------------------------------------------------------------------
  521. void validate_all_paths(void)
  522. {
  523.  
  524. #if PARALLAX
  525.     int i;
  526.  
  527.     for (i=0; i<=Highest_object_index; i++) {
  528.         if (Objects[i].type == OBJ_ROBOT) {
  529.             object      *objp = &Objects[i];
  530.             ai_static   *aip = &objp->ctype.ai_info;
  531.             //ai_local      *ailp = &Ai_local_info[i];
  532.  
  533.             if (objp->control_type == CT_AI) {
  534.                 if ((aip->hide_index != -1) && (aip->path_length > 0))
  535.                     if (!validate_path(4, &Point_segs[aip->hide_index], aip->path_length)) {
  536.                         //Int3();   //  This path is bogus!  Who corrupted it!  Danger! Danger!
  537.                                     //  Contact Mike, he caused this mess.
  538.                         //force_dump_ai_objects_all("Error in validate_all_paths");
  539.                         aip->path_length=0; //  This allows people to resume without harm...
  540.                     }
  541.             }
  542.         }
  543.     }
  544. #endif
  545.  
  546. }
  547. #endif
  548.  
  549. //  -------------------------------------------------------------------------------------------------------
  550. //  Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to
  551. //  hide in Ai_local_info[objnum].goal_segment.
  552. //  Sets    objp->ctype.ai_info.hide_index,     a pointer into Point_segs, the first point_seg of the path.
  553. //          objp->ctype.ai_info.path_length,        length of path
  554. //          Point_segs_free_ptr             global pointer into Point_segs array
  555. void create_path(object *objp)
  556. {
  557.     ai_static   *aip = &objp->ctype.ai_info;
  558.     ai_local        *ailp = &Ai_local_info[objp-Objects];
  559.     int         start_seg, end_seg;
  560.  
  561.     start_seg = objp->segnum;
  562.     end_seg = ailp->goal_segment;
  563.  
  564.     if (end_seg == -1)
  565.         create_n_segment_path(objp, 3, -1);
  566.  
  567.     if (end_seg == -1) {
  568.         ; //mprintf((0, "Object %i, hide_segment = -1, not creating path.\n", objp-Objects));
  569.     } else {
  570.         create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, -1, 0, 0, -1);
  571.         aip->hide_index = Point_segs_free_ptr - Point_segs;
  572.         aip->cur_path_index = 0;
  573. #ifndef NDEBUG
  574.         validate_path(5, Point_segs_free_ptr, aip->path_length);
  575. #endif
  576.         Point_segs_free_ptr += aip->path_length;
  577.         if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) {
  578.             //Int3();   //  Contact Mike: This is curious, though not deadly. /eip++;g
  579.             //force_dump_ai_objects_all("Error in create_path");
  580.             ai_reset_all_paths();
  581.         }
  582.         aip->PATH_DIR = 1;      //  Initialize to moving forward.
  583.         aip->SUBMODE = AISM_HIDING;     //  Pretend we are hiding, so we sit here until bothered.
  584.     }
  585.  
  586.     maybe_ai_path_garbage_collect();
  587.  
  588. }
  589.  
  590. //  -------------------------------------------------------------------------------------------------------
  591. //  Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to
  592. //  hide in Ai_local_info[objnum].goal_segment.
  593. //  Sets    objp->ctype.ai_info.hide_index,     a pointer into Point_segs, the first point_seg of the path.
  594. //          objp->ctype.ai_info.path_length,        length of path
  595. //          Point_segs_free_ptr             global pointer into Point_segs array
  596. void create_path_to_player(object *objp, int max_length, int safety_flag)
  597. {
  598.     ai_static   *aip = &objp->ctype.ai_info;
  599.     ai_local        *ailp = &Ai_local_info[objp-Objects];
  600.     int         start_seg, end_seg;
  601.  
  602. //mprintf((0, "Creating path to player.\n"));
  603.     if (max_length == -1)
  604.         max_length = MAX_DEPTH_TO_SEARCH_FOR_PLAYER;
  605.  
  606.     ailp->time_player_seen = GameTime;          //  Prevent from resetting path quickly.
  607.     ailp->goal_segment = ConsoleObject->segnum;
  608.  
  609.     start_seg = objp->segnum;
  610.     end_seg = ailp->goal_segment;
  611.  
  612.     // mprintf((0, "Creating path for object #%i, from segment #%i to #%i\n", objp-Objects, start_seg, end_seg));
  613.  
  614.     if (end_seg == -1) {
  615.         ; //mprintf((0, "Object %i, hide_segment = -1, not creating path.\n", objp-Objects));
  616.     } else {
  617. #ifndef NDEBUG
  618. point_seg *pseg0 = Point_segs_free_ptr;
  619. #endif
  620.         create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, max_length, 1, safety_flag, -1);
  621.         aip->hide_index = Point_segs_free_ptr - Point_segs;
  622.         aip->cur_path_index = 0;
  623. #ifndef NDEBUG
  624. //Enclosed this Assert in an ifdef, because if NDEBUG isn't defined,
  625. //pseg0 doesn't exist!  -KRB
  626. Assert(Point_segs_free_ptr == pseg0);
  627. #endif
  628.  
  629. #ifndef NDEBUG
  630.         validate_path(6, Point_segs_free_ptr, aip->path_length);
  631. #endif
  632.         // mprintf((0, "Created path to player, len = %i, EndSeg = %i, PlayerSeg = %i\n", aip->path_length, Point_segs[aip->hide_index+aip->path_length-1].segnum, ConsoleObject->segnum));
  633.         Point_segs_free_ptr += aip->path_length;
  634.         if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) {
  635.             //Int3();   //  Contact Mike: This is stupid.  Should call maybe_ai_garbage_collect before the add.
  636.             //force_dump_ai_objects_all("Error in create_path_to_player");
  637.             ai_reset_all_paths();
  638.             return;
  639.         }
  640. //      Assert(Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 < MAX_POINT_SEGS);
  641.         aip->PATH_DIR = 1;      //  Initialize to moving forward.
  642.         aip->SUBMODE = AISM_GOHIDE;     //  This forces immediate movement.
  643.         ailp->mode = AIM_FOLLOW_PATH;
  644.         ailp->player_awareness_type = 0;        //  If robot too aware of player, will set mode to chase
  645.         // mprintf((0, "Created %i segment path to player.\n", aip->path_length));
  646.     }
  647.  
  648.     maybe_ai_path_garbage_collect();
  649.  
  650. }
  651.  
  652. //  -------------------------------------------------------------------------------------------------------
  653. //  Creates a path from the objects current segment (objp->segnum) to the specified segment for the object to
  654. //  hide in Ai_local_info[objnum].goal_segment
  655. //  Sets    objp->ctype.ai_info.hide_index,     a pointer into Point_segs, the first point_seg of the path.
  656. //          objp->ctype.ai_info.path_length,        length of path
  657. //          Point_segs_free_ptr             global pointer into Point_segs array
  658. void create_path_to_station(object *objp, int max_length)
  659. {
  660.     ai_static   *aip = &objp->ctype.ai_info;
  661.     ai_local        *ailp = &Ai_local_info[objp-Objects];
  662.     int         start_seg, end_seg;
  663.  
  664.     if (max_length == -1)
  665.         max_length = MAX_DEPTH_TO_SEARCH_FOR_PLAYER;
  666.  
  667.     ailp->time_player_seen = GameTime;          //  Prevent from resetting path quickly.
  668.  
  669.     start_seg = objp->segnum;
  670.     end_seg = aip->hide_segment;
  671.  
  672.     //1001: mprintf((0, "Back to station for object #%i, from segment #%i to #%i\n", objp-Objects, start_seg, end_seg));
  673.  
  674.     if (end_seg == -1) {
  675.         ; //mprintf((0, "Object %i, hide_segment = -1, not creating path.\n", objp-Objects));
  676.     } else {
  677.         create_path_points(objp, start_seg, end_seg, Point_segs_free_ptr, &aip->path_length, max_length, 1, 1, -1);
  678.         aip->hide_index = Point_segs_free_ptr - Point_segs;
  679.         aip->cur_path_index = 0;
  680. #ifndef NDEBUG
  681.         validate_path(7, Point_segs_free_ptr, aip->path_length);
  682. #endif
  683.         //mprintf((0, "Created station path, len = %i, EndSeg = %i\n", aip->path_length, Point_segs[aip->hide_index+aip->path_length-1].segnum));
  684.         Point_segs_free_ptr += aip->path_length;
  685.         if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) {
  686.             //Int3();   //  Contact Mike: Stupid.
  687.             //force_dump_ai_objects_all("Error in create_path_to_station");
  688.             ai_reset_all_paths();
  689.             return;
  690.         }
  691. //      Assert(Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 < MAX_POINT_SEGS);
  692.         aip->PATH_DIR = 1;      //  Initialize to moving forward.
  693.         // aip->SUBMODE = AISM_GOHIDE;      //  This forces immediate movement.
  694.         ailp->mode = AIM_FOLLOW_PATH;
  695.         ailp->player_awareness_type = 0;
  696.     }
  697.  
  698.  
  699.     maybe_ai_path_garbage_collect();
  700.  
  701. }
  702.  
  703.  
  704. //  -------------------------------------------------------------------------------------------------------
  705. //  Create a path of length path_length for an object, stuffing info in ai_info field.
  706. void create_n_segment_path(object *objp, int path_length, int avoid_seg)
  707. {
  708.     ai_static   *aip=&objp->ctype.ai_info;
  709.     ai_local        *ailp = &Ai_local_info[objp-Objects];
  710.  
  711. //mprintf((0, "Creating %i segment path.\n", path_length));
  712.  
  713.     if (create_path_points(objp, objp->segnum, -2, Point_segs_free_ptr, &aip->path_length, path_length, 1, 0, avoid_seg) == -1) {
  714.         //Int3();   //  Contact Mike:  Considering removing this code.  Can I?
  715.         //force_dump_ai_objects_all("Error in create_n_segment_path");
  716.         Point_segs_free_ptr += aip->path_length;
  717.         //mprintf((0, "Unable to form path of length %i for object %i\n", path_length, objp-Objects));
  718.         while ((create_path_points(objp, objp->segnum, -2, Point_segs_free_ptr, &aip->path_length, --path_length, 1, 0, -1) == -1)) {
  719.             //mprintf((0, "Unable to form path of length %i for object %i\n", path_length, objp-Objects));
  720.             Assert(path_length);
  721.         }
  722.     }
  723.  
  724.     aip->hide_index = Point_segs_free_ptr - Point_segs;
  725.     aip->cur_path_index = 0;
  726. #ifndef NDEBUG
  727.     validate_path(8, Point_segs_free_ptr, aip->path_length);
  728. #endif
  729.     Point_segs_free_ptr += aip->path_length;
  730.     if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) {
  731.         //Int3();   //  Contact Mike: This is curious, though not deadly. /eip++;g
  732.         //force_dump_ai_objects_all("Error in crete_n_segment_path 2");
  733.         ai_reset_all_paths();
  734.     }
  735.  
  736.     aip->PATH_DIR = 1;      //  Initialize to moving forward.
  737.     aip->SUBMODE = -1;      //  Don't know what this means.
  738.     ailp->mode = AIM_FOLLOW_PATH;
  739.  
  740.     maybe_ai_path_garbage_collect();
  741.  
  742. }
  743.  
  744. //  -------------------------------------------------------------------------------------------------------
  745. void create_n_segment_path_to_door(object *objp, int path_length, int avoid_seg)
  746. {
  747.     create_n_segment_path(objp, path_length, avoid_seg);
  748. }
  749.  
  750. //--unused-- // -------------------------------------------------------------------------------------------------------
  751. //--unused-- // For all AI objects which have mode HIDE or RUN_FROM_OBJECT, create a path to run to.
  752. //--unused-- void create_all_paths(void)
  753. //--unused-- {
  754. //--unused--    int i;
  755. //--unused-- 
  756. //--unused--    for (i=0; i<=Highest_object_index; i++) {
  757. //--unused--        object  *objp = &Objects[i];
  758. //--unused--        if (Objects[i].control_type == CT_AI) {
  759. //--unused--            ai_static   *aip = &objp->ctype.ai_info;
  760. //--unused--            if ((aip->behavior == AIB_HIDE) || (aip->behavior == AIB_RUN_FROM) || (aip->behavior == AIB_FOLLOW_PATH))
  761. //--unused--                create_path(&Objects[i]);
  762. //--unused--        }
  763. //--unused--    }
  764. //--unused-- 
  765. //--unused-- }
  766.  
  767. extern int Connected_segment_distance;
  768.  
  769. //  ----------------------------------------------------------------------------------------------------
  770. void move_object_to_goal(object *objp, vms_vector *goal_point, int goal_seg)
  771. {
  772.     ai_static   *aip = &objp->ctype.ai_info;
  773.     int         segnum;
  774.  
  775.     Assert(objp->segnum != -1);
  776.  
  777.     // mprintf((0, "[%i -> %i]\n", objp-Objects, goal_seg));
  778.  
  779. #ifndef NDEBUG
  780.     if (objp->segnum != goal_seg)
  781.         if (find_connect_side(&Segments[objp->segnum], &Segments[goal_seg]) == -1) {
  782.             fix dist;
  783.             dist = find_connected_distance(&objp->pos, objp->segnum, goal_point, goal_seg, 30, WID_FLY_FLAG);
  784.             if (Connected_segment_distance > 2) {   //  This global is set in find_connected_distance
  785.                 // Int3();
  786.                 mprintf((1, "Warning: Object %i hopped across %i segments, a distance of %7.3f.\n", objp-Objects, Connected_segment_distance, f2fl(dist)));
  787.             }
  788.         }
  789. #endif
  790.  
  791.     aip->cur_path_index += aip->PATH_DIR;
  792.  
  793.     if (aip->cur_path_index <= 0) {
  794.         if (aip->behavior == AIB_STATION) {
  795.             mprintf((0, "Object #%i, creating path back to station.\n", objp-Objects));
  796.             create_path_to_station(objp, 15);
  797.             return;
  798.         }
  799.         aip->cur_path_index = 0;
  800.         aip->PATH_DIR = -aip->PATH_DIR;
  801.     } else if (aip->cur_path_index >= aip->path_length) {
  802.         if (aip->behavior == AIB_STATION) {
  803.             mprintf((0, "Object #%i, creating path back to station.\n", objp-Objects));
  804.             create_path_to_station(objp, 15);
  805.             return;
  806.         }
  807.         aip->cur_path_index = aip->path_length-1;
  808.         aip->PATH_DIR = -aip->PATH_DIR;
  809.     }
  810.  
  811.     objp->pos = *goal_point;
  812.     segnum = find_object_seg(objp);
  813.     if (segnum != goal_seg)
  814.         mprintf((1, "Object #%i goal supposed to be in segment #%i, but in segment #%i\n", objp-Objects, goal_seg, segnum));
  815.  
  816.     if (segnum == -1) {
  817.         Int3(); //  Oops, object is not in any segment.
  818.                     // Contact Mike: This is impossible.
  819.         //  Hack, move object to center of segment it used to be in.
  820.         compute_segment_center(&objp->pos, &Segments[objp->segnum]);
  821.     } else
  822.         obj_relink(objp-Objects, segnum);
  823. }
  824.  
  825. //  ----------------------------------------------------------------------------------------------------------
  826. //  Optimization: If current velocity will take robot near goal, don't change velocity
  827. void ai_follow_path(object *objp, int player_visibility)
  828. {
  829.     ai_static       *aip = &objp->ctype.ai_info;
  830.  
  831.     vms_vector  goal_point, new_goal_point;
  832.     fix         dist_to_goal;
  833.     // robot_info   *robptr = &Robot_info[objp->id];
  834.     int         forced_break, original_dir, original_index;
  835.     fix         dist_to_player;
  836.     int         goal_seg;
  837.     ai_local        *ailp = &Ai_local_info[objp-Objects];
  838.     fix         threshold_distance;
  839.  
  840. //int debug_count=0;
  841. //int Cur_index[100], Cur_dir[100];
  842.  
  843. // mprintf((0, "Obj %i, dist=%6.1f index=%i len=%i seg=%i pos = %6.1f %6.1f %6.1f.\n", objp-Objects, f2fl(vm_vec_dist_quick(&objp->pos, &ConsoleObject->pos)), aip->cur_path_index, aip->path_length, objp->segnum, f2fl(objp->pos.x), f2fl(objp->pos.y), f2fl(objp->pos.z)));
  844.  
  845. //--debug 01/17/95--    //  If in multiplayer mode, only follow path if player is visible.
  846. //--debug 01/17/95--    if (Game_mode & GM_MULTI)
  847. //--debug 01/17/95--        if (player_visibility) {
  848. //--debug 01/17/95--            #ifndef SHAREWARE
  849. //--debug 01/17/95--            if (!ai_multiplayer_awareness(objp, 69))
  850. //--debug 01/17/95--                return;
  851. //--debug 01/17/95--            #endif
  852. //--debug 01/17/95--        } else
  853. //--debug 01/17/95--            return;
  854.  
  855.     if ((aip->hide_index == -1) || (aip->path_length == 0))
  856.         if (ailp->mode == AIM_RUN_FROM_OBJECT) {
  857.             create_n_segment_path(objp, 5, -1);
  858.             ailp->mode = AIM_RUN_FROM_OBJECT;
  859.         } else
  860.             create_path(objp);
  861.  
  862. if ((aip->hide_index + aip->path_length > Point_segs_free_ptr - Point_segs) && (aip->path_length>0)) {
  863.     //Int3();   //  Contact Mike: Bad.  Path goes into what is believed to be free space.
  864.     //force_dump_ai_objects_all("Error in ai_follow_path");
  865.     ai_reset_all_paths();
  866. }
  867.  
  868.     if (aip->path_length < 2) {
  869.         if (ailp->mode == AIM_RUN_FROM_OBJECT) {
  870.             if (ConsoleObject->segnum == objp->segnum)
  871.                 create_n_segment_path(objp, AVOID_SEG_LENGTH, -1);          //  Can't avoid segment player is in, robot is already in it! (That's what the -1 is for) 
  872.             else
  873.                 create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum);
  874.             ailp->mode = AIM_RUN_FROM_OBJECT;   //  It gets bashed in create_n_segment_path
  875.         } else {
  876.             ailp->mode = AIM_STILL;
  877.         }
  878.         return;
  879.     }
  880.  
  881.     Assert((aip->PATH_DIR == -1) || (aip->PATH_DIR == 1));
  882.  
  883.     if ((aip->SUBMODE == AISM_HIDING) && (aip->behavior == AIB_HIDE))
  884.         return;
  885.  
  886.     goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point;
  887.     goal_seg = Point_segs[aip->hide_index + aip->cur_path_index].segnum;
  888.     dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos);
  889.  
  890.     if (Player_is_dead)
  891.         dist_to_player = vm_vec_dist_quick(&objp->pos, &Viewer->pos);
  892.     else
  893.         dist_to_player = vm_vec_dist_quick(&objp->pos, &ConsoleObject->pos);
  894.  
  895.     //  Efficiency hack: If far away from player, move in big quantized jumps.
  896.     if ((dist_to_player > F1_0*200) && !(Game_mode & GM_MULTI)) {
  897.         if (dist_to_goal < F1_0*2)
  898.             move_object_to_goal(objp, &goal_point, goal_seg);
  899.         else {
  900.             robot_info  *robptr = &Robot_info[objp->id];
  901.             fix cur_speed = robptr->max_speed[Difficulty_level]/2;
  902.             fix distance_travellable = fixmul(FrameTime, cur_speed);
  903.  
  904.             if (distance_travellable >= dist_to_goal)
  905.                 move_object_to_goal(objp, &goal_point, goal_seg);
  906.             else {
  907.                 fix prob = fixdiv(distance_travellable, dist_to_goal);
  908.  
  909.                 int rand_num = rand();
  910.                 if ( (rand_num >> 1) < prob)
  911.                     move_object_to_goal(objp, &goal_point, goal_seg);
  912.             }
  913.         }
  914.  
  915.         //  If we are hiding, we stop when we get to the goal.
  916.         if (ailp->mode == AIM_HIDE)
  917.             ailp->mode = AIM_STILL;
  918.  
  919.         return;
  920.     }
  921.  
  922. //  if ((dist_to_player > F1_0*200) && !(Game_mode & GM_MULTI)) //  ROB!
  923. //      mprintf((0, "+"));      //   ROB! Enable this to see how much more often follow path code would be called.
  924.  
  925.     //  If running from player, only run until can't be seen.
  926.     if (ailp->mode == AIM_RUN_FROM_OBJECT) {
  927.         if ((player_visibility == 0) && (ailp->player_awareness_type == 0)) {
  928.             fix vel_scale;
  929.  
  930.             vel_scale = F1_0 - FrameTime/2;
  931.             if (vel_scale < F1_0/2)
  932.                 vel_scale = F1_0/2;
  933.  
  934.             vm_vec_scale(&objp->mtype.phys_info.velocity, vel_scale);
  935.  
  936.             return;
  937.         } else {
  938.             //  If player on path (beyond point robot is now at), then create a new path.
  939.             point_seg   *curpsp = &Point_segs[aip->hide_index];
  940.             int         player_segnum = ConsoleObject->segnum;
  941.             int         i;
  942.  
  943.             //  This is probably being done every frame, which is wasteful.
  944.             for (i=aip->cur_path_index; i<aip->path_length; i++)
  945.                 if (curpsp[i].segnum == player_segnum) {
  946.                     if (player_segnum != objp->segnum)
  947.                         create_n_segment_path(objp, AVOID_SEG_LENGTH, player_segnum);
  948.                     else
  949.                         create_n_segment_path(objp, AVOID_SEG_LENGTH, -1);
  950.                     ailp->mode = AIM_RUN_FROM_OBJECT;   //  It gets bashed in create_n_segment_path
  951.                     break;
  952.                 }
  953.             if (player_visibility) {
  954.                 ailp->player_awareness_type = 1;
  955.                 ailp->player_awareness_time = F1_0;
  956.             }
  957.         }
  958.     }
  959.  
  960.     if (aip->cur_path_index < 0)
  961.         aip->cur_path_index = 0;
  962.     else if (aip->cur_path_index >= aip->path_length)
  963.         if (ailp->mode == AIM_RUN_FROM_OBJECT) {
  964.             create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum);
  965.             ailp->mode = AIM_RUN_FROM_OBJECT;   //  It gets bashed in create_n_segment_path
  966.         } else
  967.             aip->cur_path_index = aip->path_length-1;
  968.  
  969.     goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point;
  970.  
  971.     //  If near goal, pick another goal point.
  972.     forced_break = 0;       //  Gets set for short paths.
  973.     original_dir = aip->PATH_DIR;
  974.     original_index = aip->cur_path_index;
  975.     threshold_distance = fixmul(vm_vec_mag_quick(&objp->mtype.phys_info.velocity), FrameTime)*2 + F1_0*2;
  976.  
  977.     while ((dist_to_goal < threshold_distance) && !forced_break) {
  978.  
  979.         //  Advance to next point on path.
  980.         aip->cur_path_index += aip->PATH_DIR;
  981.  
  982.         //  See if next point wraps past end of path (in either direction), and if so, deal with it based on mode.
  983.         if ((aip->cur_path_index >= aip->path_length) || (aip->cur_path_index < 0)) {
  984.  
  985.             //mprintf((0, "Object %i reached end of the line!\n", objp-Objects));
  986.             //  If mode = hiding, then stay here until get bonked or hit by player.
  987.             if (ailp->mode == AIM_HIDE) {
  988.                 ailp->mode = AIM_STILL;
  989.                 return;     // Stay here until bonked or hit by player.
  990.             } else if (aip->behavior == AIB_STATION) {
  991.                 mprintf((0, "Object %i reached end of line, creating path back to station.\n", objp-Objects));
  992.                 create_path_to_station(objp, 15);
  993.                 if (aip->hide_segment != Point_segs[aip->hide_index+aip->path_length-1].segnum) {
  994.                     mprintf((0, "Couldn't make it back to path.  Put in still mode.\n"));
  995.                     ailp->mode = AIM_STILL;
  996.                 }
  997.                 return;
  998.             } else if ((ailp->mode == AIM_FOLLOW_PATH) && (aip->behavior != AIB_FOLLOW_PATH)) {
  999.                 create_path_to_player(objp, 10, 1);
  1000.             } else if (ailp->mode == AIM_RUN_FROM_OBJECT) {
  1001.                 create_n_segment_path(objp, AVOID_SEG_LENGTH, ConsoleObject->segnum);
  1002.                 ailp->mode = AIM_RUN_FROM_OBJECT;   //  It gets bashed in create_n_segment_path
  1003.             } else {
  1004.                 //  Reached end of the line.  First see if opposite end point is reachable, and if so, go there.
  1005.                 //  If not, turn around.
  1006.                 int         opposite_end_index;
  1007.                 vms_vector  *opposite_end_point;
  1008.                 fvi_info        hit_data;
  1009.                 int         fate;
  1010.                 fvi_query   fq;
  1011.  
  1012.                 // See which end we're nearer and look at the opposite end point.
  1013.                 if (abs(aip->cur_path_index - aip->path_length) < aip->cur_path_index) {
  1014.                     //  Nearer to far end (ie, index not 0), so try to reach 0.
  1015.                     opposite_end_index = 0;
  1016.                 } else {
  1017.                     //  Nearer to 0 end, so try to reach far end.
  1018.                     opposite_end_index = aip->path_length-1;
  1019.                 }
  1020.  
  1021.                 opposite_end_point = &Point_segs[aip->hide_index + opposite_end_index].point;
  1022.  
  1023.                 fq.p0                       = &objp->pos;
  1024.                 fq.startseg             = objp->segnum;
  1025.                 fq.p1                       = opposite_end_point;
  1026.                 fq.rad                  = objp->size;
  1027.                 fq.thisobjnum           = objp-Objects;
  1028.                 fq.ignore_obj_list  = NULL;
  1029.                 fq.flags                    = 0;                //what about trans walls???
  1030.  
  1031.                 fate = find_vector_intersection(&fq,&hit_data);
  1032.  
  1033.                 if (fate != HIT_WALL) {
  1034.                     //  We can be circular!  Do it!
  1035.                     //  Path direction is unchanged.
  1036.                     aip->cur_path_index = opposite_end_index;
  1037.                 } else {
  1038.                     aip->PATH_DIR = -aip->PATH_DIR;
  1039.                 }
  1040.             }
  1041.             break;
  1042.         } else {
  1043.             new_goal_point = Point_segs[aip->hide_index + aip->cur_path_index].point;
  1044.             goal_point = new_goal_point;
  1045.             dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos);
  1046.         }
  1047.  
  1048.         //  If went all the way around to original point, in same direction, then get out of here!
  1049. //      Cur_index[debug_count] = aip->cur_path_index;
  1050. //      Cur_dir[debug_count] = aip->PATH_DIR;
  1051. //      debug_count++;
  1052.         if ((aip->cur_path_index == original_index) && (aip->PATH_DIR == original_dir)) {
  1053.             create_path_to_player(objp, 3, 1);
  1054.             forced_break = 1;
  1055.         }
  1056.     }   //  end while
  1057.  
  1058.     //  Set velocity (objp->mtype.phys_info.velocity) and orientation (objp->orient) for this object.
  1059.     ai_path_set_orient_and_vel(objp, &goal_point);
  1060.  
  1061. }
  1062.  
  1063. typedef struct {
  1064.     short   path_start, objnum;
  1065. } obj_path;
  1066.  
  1067. int path_index_compare(obj_path *i1, obj_path *i2)
  1068. {
  1069.     if (i1->path_start < i2->path_start)
  1070.         return -1;
  1071.     else if (i1->path_start == i2->path_start)
  1072.         return 0;
  1073.     else
  1074.         return 1;
  1075. }
  1076.  
  1077. //  ----------------------------------------------------------------------------------------------------------
  1078. //  Set orientation matrix and velocity for objp based on its desire to get to a point.
  1079. void ai_path_set_orient_and_vel(object *objp, vms_vector *goal_point)
  1080. {
  1081.     vms_vector  cur_vel = objp->mtype.phys_info.velocity;
  1082.     vms_vector  norm_cur_vel;
  1083.     vms_vector  norm_vec_to_goal;
  1084.     vms_vector  cur_pos = objp->pos;
  1085.     vms_vector  norm_fvec;
  1086.     fix         speed_scale;
  1087.     fix         dot;
  1088.     robot_info  *robptr = &Robot_info[objp->id];
  1089.     fix         max_speed;
  1090.  
  1091.     //  If evading player, use highest difficulty level speed, plus something based on diff level
  1092.     max_speed = robptr->max_speed[Difficulty_level];
  1093.     if (Ai_local_info[objp-Objects].mode == AIM_RUN_FROM_OBJECT)
  1094.         max_speed = max_speed*3/2;
  1095.  
  1096.     vm_vec_sub(&norm_vec_to_goal, goal_point, &cur_pos);
  1097.     vm_vec_normalize_quick(&norm_vec_to_goal);
  1098.  
  1099.     norm_cur_vel = cur_vel;
  1100.     vm_vec_normalize_quick(&norm_cur_vel);
  1101.  
  1102.     norm_fvec = objp->orient.fvec;
  1103.     vm_vec_normalize_quick(&norm_fvec);
  1104.  
  1105.     dot = vm_vec_dot(&norm_vec_to_goal, &norm_fvec);
  1106.  
  1107.     //  If very close to facing opposite desired vector, perturb vector
  1108.     if (dot < -15*F1_0/16) {
  1109.         //mprintf((0, "Facing away from goal, abruptly turning\n"));
  1110.         norm_cur_vel = norm_vec_to_goal;
  1111.     } else {
  1112.         norm_cur_vel.x += norm_vec_to_goal.x/2;
  1113.         norm_cur_vel.y += norm_vec_to_goal.y/2;
  1114.         norm_cur_vel.z += norm_vec_to_goal.z/2;
  1115.     }
  1116.  
  1117.     vm_vec_normalize_quick(&norm_cur_vel);
  1118.  
  1119.     //  Set speed based on this robot type's maximum allowed speed and how hard it is turning.
  1120.     //  How hard it is turning is based on the dot product of (vector to goal) and (current velocity vector)
  1121.     //  Note that since 3*F1_0/4 is added to dot product, it is possible for the robot to back up.
  1122.  
  1123.     //  Set speed and orientation.
  1124.     if (dot < 0)
  1125.         dot /= -4;
  1126.  
  1127.     speed_scale = fixmul(max_speed, dot);
  1128.     vm_vec_scale(&norm_cur_vel, speed_scale);
  1129.     objp->mtype.phys_info.velocity = norm_cur_vel;
  1130.  
  1131.     if (Ai_local_info[objp-Objects].mode == AIM_RUN_FROM_OBJECT)
  1132.         ai_turn_towards_vector(&norm_vec_to_goal, objp, robptr->turn_time[NDL-1]/2);
  1133.     else
  1134.         ai_turn_towards_vector(&norm_vec_to_goal, objp, robptr->turn_time[Difficulty_level]);
  1135.  
  1136. }
  1137.  
  1138. int Last_frame_garbage_collected = 0;
  1139.  
  1140. //  ----------------------------------------------------------------------------------------------------------
  1141. //  Garbage colledion -- Free all unused records in Point_segs and compress all paths.
  1142. void ai_path_garbage_collect(void)
  1143. {
  1144.     int free_path_index = 0;
  1145.     int num_path_objects = 0;
  1146.     int objnum;
  1147.     int objind;
  1148.     obj_path        object_list[MAX_OBJECTS];
  1149.  
  1150. #ifndef NDEBUG
  1151.     force_dump_ai_objects_all("***** Start ai_path_garbage_collect *****");
  1152. #endif
  1153.  
  1154.     // -- mprintf((0, "Garbage collection frame %i, last frame %i!  Old free index = %i ", FrameCount, Last_frame_garbage_collected, Point_segs_free_ptr - Point_segs));
  1155.  
  1156.     Last_frame_garbage_collected = FrameCount;
  1157.  
  1158. #ifndef NDEBUG
  1159.     validate_all_paths();
  1160. #endif
  1161.     //  Create a list of objects which have paths of length 1 or more.
  1162.     for (objnum=0; objnum <= Highest_object_index; objnum++) {
  1163.         object  *objp = &Objects[objnum];
  1164.  
  1165.         if ((objp->type == OBJ_ROBOT) && (objp->control_type == CT_AI)) {
  1166.             ai_static   *aip = &objp->ctype.ai_info;
  1167.  
  1168.             if (aip->path_length) {
  1169.                 object_list[num_path_objects].path_start = aip->hide_index;
  1170.                 object_list[num_path_objects++].objnum = objnum;
  1171.             }
  1172.         }
  1173.     }
  1174.  
  1175.     qsort(object_list, num_path_objects, sizeof(object_list[0]), path_index_compare);
  1176.  
  1177.     for (objind=0; objind < num_path_objects; objind++) {
  1178.         object      *objp;
  1179.         ai_static   *aip;
  1180.         int         i;
  1181.         int         old_index;
  1182.  
  1183.         objnum = object_list[objind].objnum;
  1184.         objp = &Objects[objnum];
  1185.         aip = &objp->ctype.ai_info;
  1186.         old_index = aip->hide_index;
  1187.  
  1188.         aip->hide_index = free_path_index;
  1189.         for (i=0; i<aip->path_length; i++)
  1190.             Point_segs[free_path_index++] = Point_segs[old_index++];
  1191.     }
  1192.  
  1193.     Point_segs_free_ptr = &Point_segs[free_path_index];
  1194.  
  1195.     mprintf((0, "new = %i\n", free_path_index));
  1196. //printf("After garbage collection, free index = %i\n", Point_segs_free_ptr - Point_segs);
  1197. #ifndef NDEBUG
  1198.     {
  1199.     int i;
  1200.  
  1201.     force_dump_ai_objects_all("***** Finish ai_path_garbage_collect *****");
  1202.  
  1203.     for (i=0; i<=Highest_object_index; i++) {
  1204.         ai_static   *aip = &Objects[i].ctype.ai_info;
  1205.  
  1206.         if ((Objects[i].type == OBJ_ROBOT) && (Objects[i].control_type == CT_AI))
  1207.             if ((aip->hide_index + aip->path_length > Point_segs_free_ptr - Point_segs) && (aip->path_length>0))
  1208.                 Int3();     //  Contact Mike: Debug trap for nasty, elusive bug.
  1209.     }
  1210.  
  1211.     validate_all_paths();
  1212.     }
  1213. #endif
  1214.  
  1215. }
  1216.  
  1217. //  -----------------------------------------------------------------------------
  1218. //  Do garbage collection if not been done for awhile, or things getting really critical.
  1219. void maybe_ai_path_garbage_collect(void)
  1220. {
  1221.     if (Point_segs_free_ptr - Point_segs > MAX_POINT_SEGS - MAX_PATH_LENGTH) {
  1222.         if (Last_frame_garbage_collected+1 >= FrameCount) {
  1223.             //  This is kind of bad.  Garbage collected last frame or this frame.
  1224.             //  Just destroy all paths.  Too bad for the robots.  They are memory wasteful.
  1225.             ai_reset_all_paths();
  1226.             mprintf((1, "Warning: Resetting all paths.  Point_segs buffer nearly exhausted.\n"));
  1227.         } else {
  1228.             //  We are really close to full, but didn't just garbage collect, so maybe this is recoverable.
  1229.             mprintf((1, "Warning: Almost full garbage collection being performed: "));
  1230.             ai_path_garbage_collect();
  1231.             mprintf((1, "Free records = %i/%i\n", MAX_POINT_SEGS - (Point_segs_free_ptr - Point_segs), MAX_POINT_SEGS));
  1232.         }
  1233.     } else if (Point_segs_free_ptr - Point_segs > 3*MAX_POINT_SEGS/4) {
  1234.         if (Last_frame_garbage_collected + 16 < FrameCount) {
  1235.             ai_path_garbage_collect();
  1236.         }
  1237.     } else if (Point_segs_free_ptr - Point_segs > MAX_POINT_SEGS/2) {
  1238.         if (Last_frame_garbage_collected + 256 < FrameCount) {
  1239.             ai_path_garbage_collect();
  1240.         }
  1241.     }
  1242. }
  1243.  
  1244. //  -----------------------------------------------------------------------------
  1245. //  Reset all paths.  Do garbage collection.
  1246. //  Should be called at the start of each level.
  1247. void ai_reset_all_paths(void)
  1248. {
  1249.     int i;
  1250.  
  1251.     for (i=0; i<=Highest_object_index; i++)
  1252.         if (Objects[i].control_type == CT_AI) {
  1253.             Objects[i].ctype.ai_info.hide_index = -1;
  1254.             Objects[i].ctype.ai_info.path_length = 0;
  1255.         }
  1256.  
  1257.     ai_path_garbage_collect();
  1258.  
  1259. }
  1260.  
  1261. //  ---------------------------------------------------------------------------------------------------------
  1262. //  Probably called because a robot bashed a wall, getting a bunch of retries.
  1263. //  Try to resume path.
  1264. void attempt_to_resume_path(object *objp)
  1265. {
  1266.     //int               objnum = objp-Objects;
  1267.     ai_static       *aip = &objp->ctype.ai_info;
  1268. //  int             goal_segnum, object_segnum,
  1269.     int             abs_index, new_path_index;
  1270.  
  1271.     mprintf((0, "Object %i trying to resume path at index %i\n", objp-Objects, aip->cur_path_index));
  1272.  
  1273.     if (aip->behavior == AIB_STATION)
  1274.         if (rand() > 8192) {
  1275.             ai_local            *ailp = &Ai_local_info[objp-Objects];
  1276.  
  1277.             aip->hide_segment = objp->segnum;
  1278.             ailp->mode = AIM_STILL;
  1279.             mprintf((1, "Note: Bashing hide segment of robot %i to current segment because he's lost.\n", objp-Objects));
  1280.         }
  1281.  
  1282. //  object_segnum = objp->segnum;
  1283.     abs_index = aip->hide_index+aip->cur_path_index;
  1284. //  goal_segnum = Point_segs[abs_index].segnum;
  1285.  
  1286. //  if (object_segnum == goal_segnum)
  1287. //      mprintf((0, "Very peculiar, goal segnum = object's segnum = %i.\n", goal_segnum));
  1288.  
  1289.     new_path_index = aip->cur_path_index - aip->PATH_DIR;
  1290.  
  1291.     if ((new_path_index >= 0) && (new_path_index < aip->path_length)) {
  1292.         // mprintf((0, "Trying path index of %i\n", new_path_index));
  1293.         aip->cur_path_index = new_path_index;
  1294.     } else {
  1295.         //  At end of line and have nowhere to go.
  1296.         // mprintf((0, "At end of line and can't get to goal.  Creating new path.  Frame %i\n", FrameCount));
  1297.         move_towards_segment_center(objp);
  1298.         create_path_to_station(objp, 15);
  1299.     }
  1300.  
  1301. }
  1302.  
  1303. //  ----------------------------------------------------------------------------------------------------------
  1304. //                  DEBUG FUNCTIONS FOLLOW
  1305. //  ----------------------------------------------------------------------------------------------------------
  1306.  
  1307. #ifdef EDITOR
  1308. int Test_size = 1000;
  1309.  
  1310. void test_create_path_many(void)
  1311. {
  1312.     point_seg   point_segs[200];
  1313.     short           num_points;
  1314.  
  1315.     int         i;
  1316.  
  1317.     for (i=0; i<Test_size; i++) {
  1318.         Cursegp = &Segments[(rand() * (Highest_segment_index + 1)) / RAND_MAX];
  1319.         Markedsegp = &Segments[(rand() * (Highest_segment_index + 1)) / RAND_MAX];
  1320.         create_path_points(&Objects[0], Cursegp-Segments, Markedsegp-Segments, point_segs, &num_points, -1, 0, 0, -1);
  1321.     }
  1322.  
  1323. }
  1324.  
  1325. void test_create_path(void)
  1326. {
  1327.     point_seg   point_segs[200];
  1328.     short           num_points;
  1329.  
  1330.     create_path_points(&Objects[0], Cursegp-Segments, Markedsegp-Segments, point_segs, &num_points, -1, 0, 0, -1);
  1331.  
  1332. }
  1333.  
  1334. void show_path(int start_seg, int end_seg, point_seg *psp, short length)
  1335. {
  1336.     printf("[%3i:%3i (%3i):] ", start_seg, end_seg, length);
  1337.  
  1338.     while (length--)
  1339.         printf("%3i ", psp[length].segnum);
  1340.  
  1341.     printf("\n");
  1342. }
  1343.  
  1344. //  For all segments in mine, create paths to all segments in mine, print results.
  1345. void test_create_all_paths(void)
  1346. {
  1347.     int start_seg, end_seg;
  1348.     short   resultant_length;
  1349.  
  1350.     Point_segs_free_ptr = Point_segs;
  1351.  
  1352.     for (start_seg=0; start_seg<=Highest_segment_index-1; start_seg++) {
  1353.         mprintf((0, "."));
  1354.         if (Segments[start_seg].segnum != -1) {
  1355.             for (end_seg=start_seg+1; end_seg<=Highest_segment_index; end_seg++) {
  1356.                 if (Segments[end_seg].segnum != -1) {
  1357.                     create_path_points(&Objects[0], start_seg, end_seg, Point_segs_free_ptr, &resultant_length, -1, 0, 0, -1);
  1358.                     show_path(start_seg, end_seg, Point_segs_free_ptr, resultant_length);
  1359.                 }
  1360.             }
  1361.         }
  1362.     }
  1363. }
  1364.  
  1365. //--anchor--int Num_anchors;
  1366. //--anchor--int Anchor_distance = 3;
  1367. //--anchor--int End_distance = 1;
  1368. //--anchor--int Anchors[MAX_SEGMENTS];
  1369.  
  1370. //--anchor--int get_nearest_anchor_distance(int segnum)
  1371. //--anchor--{
  1372. //--anchor--    short   resultant_length, minimum_length;
  1373. //--anchor--    int anchor_index;
  1374. //--anchor--
  1375. //--anchor--    minimum_length = 16383;
  1376. //--anchor--
  1377. //--anchor--    for (anchor_index=0; anchor_index<Num_anchors; anchor_index++) {
  1378. //--anchor--        create_path_points(&Objects[0], segnum, Anchors[anchor_index], Point_segs_free_ptr, &resultant_length, -1, 0, 0, -1);
  1379. //--anchor--        if (resultant_length != 0)
  1380. //--anchor--            if (resultant_length < minimum_length)
  1381. //--anchor--                minimum_length = resultant_length;
  1382. //--anchor--    }
  1383. //--anchor--
  1384. //--anchor--    return minimum_length;
  1385. //--anchor--
  1386. //--anchor--}
  1387. //--anchor--
  1388. //--anchor--void create_new_anchor(int segnum)
  1389. //--anchor--{
  1390. //--anchor--    Anchors[Num_anchors++] = segnum;
  1391. //--anchor--}
  1392. //--anchor--
  1393. //--anchor--//  A set of anchors is within N units of all segments in the graph.
  1394. //--anchor--//  Anchor_distance = how close anchors can be.
  1395. //--anchor--//  End_distance = how close you can be to the end.
  1396. //--anchor--void test_create_all_anchors(void)
  1397. //--anchor--{
  1398. //--anchor--    int nearest_anchor_distance;
  1399. //--anchor--    int segnum,i;
  1400. //--anchor--
  1401. //--anchor--    Num_anchors = 0;
  1402. //--anchor--
  1403. //--anchor--    for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  1404. //--anchor--        if (Segments[segnum].segnum != -1) {
  1405. //--anchor--            nearest_anchor_distance = get_nearest_anchor_distance(segnum);
  1406. //--anchor--            if (nearest_anchor_distance > Anchor_distance)
  1407. //--anchor--                create_new_anchor(segnum);
  1408. //--anchor--        }
  1409. //--anchor--    }
  1410. //--anchor--
  1411. //--anchor--    //  Set selected segs.
  1412. //--anchor--    for (i=0; i<Num_anchors; i++)
  1413. //--anchor--        Selected_segs[i] = Anchors[i];
  1414. //--anchor--    N_selected_segs = Num_anchors;
  1415. //--anchor--
  1416. //--anchor--}
  1417. //--anchor--
  1418. //--anchor--int Test_path_length = 5;
  1419. //--anchor--
  1420. //--anchor--void test_create_n_segment_path(void)
  1421. //--anchor--{
  1422. //--anchor--    point_seg   point_segs[200];
  1423. //--anchor--    short           num_points;
  1424. //--anchor--
  1425. //--anchor--    create_path_points(&Objects[0], Cursegp-Segments, -2, point_segs, &num_points, Test_path_length, 0, 0, -1);
  1426. //--anchor--}
  1427.  
  1428. short   Player_path_length=0;
  1429. int Player_hide_index=-1;
  1430. int Player_cur_path_index=0;
  1431. int Player_following_path_flag=0;
  1432.  
  1433. //  ------------------------------------------------------------------------------------------------------------------
  1434. //  Set orientation matrix and velocity for objp based on its desire to get to a point.
  1435. void player_path_set_orient_and_vel(object *objp, vms_vector *goal_point)
  1436. {
  1437.     vms_vector  cur_vel = objp->mtype.phys_info.velocity;
  1438.     vms_vector  norm_cur_vel;
  1439.     vms_vector  norm_vec_to_goal;
  1440.     vms_vector  cur_pos = objp->pos;
  1441.     vms_vector  norm_fvec;
  1442.     fix         speed_scale;
  1443.     fix         dot;
  1444.     fix         max_speed;
  1445.  
  1446.     max_speed = F1_0*50;
  1447.  
  1448.     vm_vec_sub(&norm_vec_to_goal, goal_point, &cur_pos);
  1449.     vm_vec_normalize_quick(&norm_vec_to_goal);
  1450.  
  1451.     norm_cur_vel = cur_vel;
  1452.     vm_vec_normalize_quick(&norm_cur_vel);
  1453.  
  1454.     norm_fvec = objp->orient.fvec;
  1455.     vm_vec_normalize_quick(&norm_fvec);
  1456.  
  1457.     dot = vm_vec_dot(&norm_vec_to_goal, &norm_fvec);
  1458.  
  1459.     //  If very close to facing opposite desired vector, perturb vector
  1460.     if (dot < -15*F1_0/16) {
  1461.         //mprintf((0, "Facing away from goal, abruptly turning\n"));
  1462.         norm_cur_vel = norm_vec_to_goal;
  1463.     } else {
  1464.         norm_cur_vel.x += norm_vec_to_goal.x/2;
  1465.         norm_cur_vel.y += norm_vec_to_goal.y/2;
  1466.         norm_cur_vel.z += norm_vec_to_goal.z/2;
  1467.     }
  1468.  
  1469.     vm_vec_normalize_quick(&norm_cur_vel);
  1470.  
  1471.     //  Set speed based on this robot type's maximum allowed speed and how hard it is turning.
  1472.     //  How hard it is turning is based on the dot product of (vector to goal) and (current velocity vector)
  1473.     //  Note that since 3*F1_0/4 is added to dot product, it is possible for the robot to back up.
  1474.  
  1475.     //  Set speed and orientation.
  1476.     if (dot < 0)
  1477.         dot /= 4;
  1478.  
  1479.     speed_scale = fixmul(max_speed, dot);
  1480.     vm_vec_scale(&norm_cur_vel, speed_scale);
  1481.     objp->mtype.phys_info.velocity = norm_cur_vel;
  1482.     ai_turn_towards_vector(&norm_vec_to_goal, objp, F1_0);
  1483.  
  1484. }
  1485.  
  1486. //  ----------------------------------------------------------------------------------------------------------
  1487. //  Optimization: If current velocity will take robot near goal, don't change velocity
  1488. void player_follow_path(object *objp)
  1489. {
  1490.     vms_vector  goal_point;
  1491.     fix         dist_to_goal;
  1492.     int         count, forced_break, original_index;
  1493.     int         goal_seg;
  1494.     fix         threshold_distance;
  1495.  
  1496.     if (!Player_following_path_flag)
  1497.         return;
  1498.  
  1499.     if (Player_hide_index == -1)
  1500.         return;
  1501.  
  1502.     if (Player_path_length < 2)
  1503.         return;
  1504.  
  1505.     goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point;
  1506.     goal_seg = Point_segs[Player_hide_index + Player_cur_path_index].segnum;
  1507.     Assert((goal_seg >= 0) && (goal_seg <= Highest_segment_index));
  1508.     dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos);
  1509.  
  1510.     if (Player_cur_path_index < 0)
  1511.         Player_cur_path_index = 0;
  1512.     else if (Player_cur_path_index >= Player_path_length)
  1513.         Player_cur_path_index = Player_path_length-1;
  1514.  
  1515.     goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point;
  1516.  
  1517.     count=0;
  1518.  
  1519.     //  If near goal, pick another goal point.
  1520.     forced_break = 0;       //  Gets set for short paths.
  1521.     //original_dir = 1;
  1522.     original_index = Player_cur_path_index;
  1523.     threshold_distance = fixmul(vm_vec_mag_quick(&objp->mtype.phys_info.velocity), FrameTime)*2 + F1_0*2;
  1524.  
  1525.     while ((dist_to_goal < threshold_distance) && !forced_break) {
  1526.  
  1527.         if (count > 1)
  1528.             mprintf((0, "."));
  1529.  
  1530.         //  ----- Debug stuff -----
  1531.         if (count++ > 20) {
  1532.             mprintf((1,"Problem following path for player.  Aborting.\n"));
  1533.             break;
  1534.         }
  1535.  
  1536.         //  Advance to next point on path.
  1537.         Player_cur_path_index += 1;
  1538.  
  1539.         //  See if next point wraps past end of path (in either direction), and if so, deal with it based on mode.
  1540.         if ((Player_cur_path_index >= Player_path_length) || (Player_cur_path_index < 0)) {
  1541.             Player_following_path_flag = 0;
  1542.             forced_break = 1;
  1543.         }
  1544.  
  1545.         //  If went all the way around to original point, in same direction, then get out of here!
  1546.         if (Player_cur_path_index == original_index) {
  1547.             mprintf((0, "Forcing break because player path wrapped, count = %i.\n", count));
  1548.             Player_following_path_flag = 0;
  1549.             forced_break = 1;
  1550.         }
  1551.  
  1552.         goal_point = Point_segs[Player_hide_index + Player_cur_path_index].point;
  1553.         dist_to_goal = vm_vec_dist_quick(&goal_point, &objp->pos);
  1554.  
  1555.     }   //  end while
  1556.  
  1557.     //  Set velocity (objp->mtype.phys_info.velocity) and orientation (objp->orient) for this object.
  1558.     player_path_set_orient_and_vel(objp, &goal_point);
  1559.  
  1560. }
  1561.  
  1562.  
  1563. //  ------------------------------------------------------------------------------------------------------------------
  1564. //  Create path for player from current segment to goal segment.
  1565. void create_player_path_to_segment(int segnum)
  1566. {
  1567.     object      *objp = ConsoleObject;
  1568.  
  1569.     Player_path_length=0;
  1570.     Player_hide_index=-1;
  1571.     Player_cur_path_index=0;
  1572.     Player_following_path_flag=0;
  1573.  
  1574.     if (create_path_points(objp, objp->segnum, segnum, Point_segs_free_ptr, &Player_path_length, 100, 0, 0, -1) == -1)
  1575.         mprintf((0, "Unable to form path of length %i for myself\n", 100));
  1576.  
  1577.     Player_following_path_flag = 1;
  1578.  
  1579.     Player_hide_index = Point_segs_free_ptr - Point_segs;
  1580.     Player_cur_path_index = 0;
  1581.     Point_segs_free_ptr += Player_path_length;
  1582.     if (Point_segs_free_ptr - Point_segs + MAX_PATH_LENGTH*2 > MAX_POINT_SEGS) {
  1583.         //Int3();   //  Contact Mike: This is curious, though not deadly. /eip++;g
  1584.         ai_reset_all_paths();
  1585.     }
  1586.  
  1587. }
  1588.  
  1589. int Player_goal_segment = -1;
  1590.  
  1591. void check_create_player_path(void)
  1592. {
  1593.     if (Player_goal_segment != -1)
  1594.         create_player_path_to_segment(Player_goal_segment);
  1595.  
  1596.     Player_goal_segment = -1;
  1597. }
  1598.  
  1599. #endif
  1600.  
  1601. //  ----------------------------------------------------------------------------------------------------------
  1602. //                  DEBUG FUNCTIONS ENDED
  1603. //  ----------------------------------------------------------------------------------------------------------
  1604.  
  1605.